
use anyhow::{anyhow, Result};
use sled::Db;
use crate::parts::Cate;


/// 这是一个代表我们本地缓存的结构体。
pub struct Cache {
    db: Db,
}

impl Cache {
    /// 创建一个新的Cache实例，它会打开或创建数据库文件。
    pub fn new(db: &str) -> Result<Self> {
        // sled::open会打开一个数据库。如果文件夹不存在，它会自动创建。
        let db = sled::open(db)
            .map_err(|e| anyhow!("无法打开或创建本地数据库 '{}': {}", db, e))?;
        Ok(Cache { db })
    }

    pub fn check(&self,cate: Cate,id: &str) -> Result<bool> {
        let tag = cate.to_string() + id;
        self.contains_and_insert(&tag)
    }

    /// 检查一个ID是否已经被处理过。
    /// 如果没有，就将其插入数据库并返回false。
    /// 如果已经存在，直接返回true。
    /// 这是一个“原子”操作，非常高效。
    fn contains_and_insert(&self, id: &str) -> Result<bool> {
        let key = id.as_bytes();

        // db.contains_key 检查键是否存在，速度极快。
        if self.db.contains_key(key)? {
            // 如果键已存在，说明我们处理过这个ID，返回true。
            Ok(true)
        } else {
            // 如果键不存在，我们将其插入数据库。
            // 我们只关心键，值可以为空。
            self.db.insert(key, &[])?;
            // 因为这是第一次处理这个ID，所以返回false。
            Ok(false)
        }
    }

    /// 获取已处理ID的总数。
    pub fn len(&self) -> usize {
        self.db.len()
    }
}

